/**
 * 
 */
package cn.boysoft.core.server;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

import cn.boysoft.core.ServiceCode;
import cn.boysoft.core.annotation.JEEEntityDeclare;
import cn.boysoft.core.annotation.JEEResultConvert;
import cn.boysoft.core.annotation.JEEService;
import cn.boysoft.core.convert.ResultConvert;
import cn.boysoft.core.manager.impl.ManagerImpl;
import cn.boysoft.core.spring.JeeXmlApplicationContext;

/**
 * @author 付厚俊
 * CreateTime 2013-4-4 下午5:22:47
 */


public class MainServer{
	private final static Logger LOGGER = LoggerFactory.getLogger(MainServer.class);
	private static ClassPathXmlApplicationContext context;
	public static List<String> serviceInfos = new ArrayList<String>();
	private static Map<String,ServiceInfo> serviceMap = new LinkedHashMap<String,ServiceInfo>();
	static List<Server> serverList;
	private static boolean success = false;
	private MainServer(){
		
	}
	public static void main(String[] args) {
		
		startMainServer();
	}
	/**
	 * @param args
	 */
	@SuppressWarnings("unchecked")
	public static void startMainServer() {
		long time = System.currentTimeMillis();
		System.out.println("JEEServer start ...."); 
		System.out.println("==============================================");
		try{
			context  = new JeeXmlApplicationContext(new String[] {"application.xml"});	
			serverList = (List<Server>) context.getBean("serverList");
			start();
			initService();
			printlnService();
			MainServer.success = true;
		}catch(Throwable e){
			e.printStackTrace();
			System.out.println("Main  Server error"); 
		}
		time = System.currentTimeMillis()-time;
		System.out.println("=============================================="); 
		System.out.println("JEEServer startup in "+time+" ms"); 
	}
	public static boolean getServerStatus(){
		return MainServer.success;
	}
	static void start() throws Throwable {
		if(serverList != null){
			for(Server s: serverList){
				s.start();
			}
		}
	}
	 public static void stop() {
		if(serverList != null){
			for(Server s: serverList){
				s.stop();
			}
		}
	}

	public static Object getBean(String serviceClassId) {
		return context.getBean(serviceClassId);
	}
	public static ServiceInfo getOnlyReadServiceInfo(String serviceId){
		return serviceMap.get(serviceId);
	}
	
	@SuppressWarnings("unchecked")
	static void initService(){
		List<String> list =  serviceInfos;
		if(list != null){
			for(String serviceName : list){
				Object serviceObject = MainServer.getBean(serviceName);
				if(serviceObject != null){
					Class serviceClass = serviceObject.getClass();
					Service serviceAnnotation = (Service)serviceClass.getAnnotation(Service.class);
					if(serviceName.equals("manager")){
						continue;
					}
			
					if(serviceObject instanceof ManagerImpl){
						String entityName = "";
						Class entityClazz = null;
						Method[] methods = null;
						
						ManagerImpl hm = (ManagerImpl)serviceObject;
						entityClazz = hm.getEntityClazz();
						methods = ManagerImpl.class.getDeclaredMethods();
						
						if(methods != null){
							if(entityClazz != null){
								JEEEntityDeclare entityDeclare = (JEEEntityDeclare) entityClazz.getAnnotation(JEEEntityDeclare.class);
								if(entityDeclare != null){
									entityName = entityDeclare.name();
								}
							}
							for(Method method : methods){
								JEEService commandAnnotation = method.getAnnotation(JEEService.class);
								if(commandAnnotation != null){
									String commandId = commandAnnotation.commandId();
									if(commandId != null ){
										if(serviceAnnotation.value() != null){
											ServiceInfo serviceInfo = new ServiceInfo();
											serviceInfo.setMethod(method);
											serviceInfo.setServiceClassId(serviceAnnotation.value());
											serviceInfo.setServiceName(commandAnnotation.name()+entityName);
											serviceInfo.setServiceDescription(commandAnnotation.description());
											serviceInfo.setNeedValue(commandAnnotation.needValue());
											serviceInfo.setCommandId(commandAnnotation.commandId());
											Type[] parameterTypes = method.getGenericParameterTypes();
											if(parameterTypes != null && parameterTypes.length==1){
												if(parameterTypes[0] instanceof TypeVariable){
													TypeVariable typeVariable = (TypeVariable)parameterTypes[0];
													if("T".equals(typeVariable.getName()) || "P".equals(typeVariable.getName())){
														if("P".equals(typeVariable.getName())){
															serviceInfo.setDataClazz(hm.getPageParamClazz());
														}else{
															serviceInfo.setDataClazz(entityClazz);
														}
													}else{
														serviceInfo.setDataClazz((Class)parameterTypes[0]);
													}
												}else{
													serviceInfo.setDataClazz((Class)parameterTypes[0]);
												}	
											}
											Class rtClass = method.getReturnType();
											serviceInfo.setRtClass(rtClass);
											String serviceId = serviceInfo.getCommandId();
											if(serviceObject != null){
												if(serviceObject instanceof ServiceCode){
													ServiceCode serviceCode = (ServiceCode)serviceObject;
													String serviceClassCode = serviceCode.getServiceClassCode();
													if(serviceClassCode != null){
														serviceId = serviceClassCode+serviceId;
													}else{
														LOGGER.warn(serviceObject.getClass() +" serviceClassCode is null");
													}
												}else{
													LOGGER.warn(serviceObject.getClass() +" have not implements interface ServiceCode");
												}
											}else{
												LOGGER.error("Can't find service "+serviceName);
											}
											serviceMap.put(serviceId, serviceInfo);
											
										}else{
											LOGGER.error("Error", serviceClass +" serviceId is null");
										}	
									}else{
										LOGGER.error("Error", method.getName()+" CommandId is null");
									}
								}
							}
							}
						}
					
					
					Method[] methods = serviceClass.getDeclaredMethods();
					if(methods != null){
						for(Method method : methods){
							JEEService commandAnnotation = method.getAnnotation(JEEService.class);	
							if(commandAnnotation != null){
								String commandId = commandAnnotation.commandId();
								if(commandId != null ){
									if(serviceAnnotation.value() != null){
										ServiceInfo serviceInfo = new ServiceInfo();
										JEEResultConvert resultConvertAnnotation = method.getAnnotation(JEEResultConvert.class);
										Class rtClass = method.getReturnType();
										
										if(resultConvertAnnotation != null){
											Class clazz = resultConvertAnnotation.convertClass();
											try {
												ResultConvert resultConvert = (ResultConvert) clazz.newInstance();
												serviceInfo.setResultConvert(resultConvert);
												Type[] types = clazz.getGenericInterfaces();
												if (types[0] instanceof ParameterizedType) {
													ParameterizedType parameterizedType = (ParameterizedType) types[0];
													rtClass = (Class) parameterizedType.getActualTypeArguments()[1];
												}	
											} catch (Exception e) {
												e.printStackTrace();
											} 	
										}
										serviceInfo.setRtClass(rtClass);
										serviceInfo.setMethod(method);
										serviceInfo.setServiceClassId(serviceAnnotation.value());
										serviceInfo.setServiceName(commandAnnotation.name());
										serviceInfo.setServiceDescription(commandAnnotation.description());
										serviceInfo.setNeedValue(commandAnnotation.needValue());
										serviceInfo.setCommandId(commandAnnotation.commandId());
										Class<?>[] parameterTypes = method.getParameterTypes();
										if(parameterTypes != null && parameterTypes.length==1){
											serviceInfo.setDataClazz(parameterTypes[0]);
										}
										
										
										String serviceId = serviceInfo.getCommandId();
										if(serviceObject != null){
											if(serviceObject instanceof ServiceCode){
												ServiceCode serviceCode = (ServiceCode)serviceObject;
												String serviceClassCode = serviceCode.getServiceClassCode();
												if(serviceClassCode != null){
													serviceId = serviceClassCode+serviceId;
												}else{
													LOGGER.warn(serviceObject.getClass() +" serviceClassCode is null");
												}
											}else{
												LOGGER.warn(serviceObject.getClass() +" have not implements interface ServiceCode");
											}
										}else{
											LOGGER.error("Can't find service "+serviceName);
										}
										serviceMap.put(serviceId, serviceInfo);
										
									}else{
										LOGGER.error("Error", serviceClass +" serviceId is null");
									}	
								}else{
									LOGGER.error("Error", method.getName()+" CommandId is null");
								}
							}
						}
					}	
				}
			}
		}
		list = null;
	}
	static void printlnService(){
		
		if(serviceMap !=  null){
			System.out.println("services:");
			System.out.println("Id             Name                Description");
			Set<Entry<String, ServiceInfo>>  entrys = serviceMap.entrySet();
			for(Entry<String, ServiceInfo> entry : entrys){
				ServiceInfo service = entry.getValue();
				if(service != null){
					System.out.println(entry.getKey()+"             "
							+service.getServiceName()+"                "
							+service.getServiceDescription());
				}	
			}
		}
	}

}
